package com.bitoon.basketdudes.web.admin;

import com.bitoon.basketdudes.web.*;
import com.bitoon.basketdudes.web.datos.DatosCalendarioTorneo;
import com.bitoon.basketdudes.web.jpa.*;
import com.bitoon.basketdudes.web.xhr.ListaEquipos;
import com.bitoon.basketdudes.web.xhr.ListaTorneosUsuario;
import java.util.*;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import org.apache.log4j.Logger;
import java.util.regex.*;

public class TorneoUsuarioAdmin extends TorneoUsuario {

    private Logger log = Logger.getLogger(TorneoUsuarioAdmin.class);

    private boolean notSelected;
    private String administrador;       //usuario al que se le asigna un torneo creado en el administrador
    private String url;                 //url de redireccion
    private List<Equipo> listaEquipos;  //lista de equipos para paginar las inscripciones
    private String urlEquipo;
    private int temporadaId;
    private boolean error;
    private int idEquipo;
    private String error_nivel;

    private String patternCrear = "^#[0-9]+#"; //para multicreacion de torneos
    private String patternNombreTorneoAdmin = "[0-9a-zA-ZñÑ _.#]*";

    //acceso a la clase estatica BaseActionAdmin
    protected BaseActionAdmin bsaadmin = BaseActionAdmin.getInstance();

    @Override
    public String execute() {
        String retorno = SUCCESS;

        return retorno;
    }
    
    public String expulsarTorneo() {
        String retorno = SUCCESS;
        EntityManager em = null;

        log.debug("[Expulsar] urlTorneo: " + getUrlTorneo() + "equipos: " + getElegir_equipo());

        //si se han elegido equipos a expulsar
        if(getElegir_equipo()!=null){

            try {
                em = bsaadmin.getEmfAdmin().createEntityManager();

                // Actualizar el estado de los participes
                for (String id : getElegir_equipo()) {
                    em.getTransaction().begin();

                    log.debug("[expulsar] Equipo: " + id + " temporada: " + getTemporadaId());

                    Query q = em.createNamedQuery("Equipo.findById");
                    q.setParameter("idEquipo", Integer.parseInt(id));
                    Equipo equipoExpulsado = (Equipo)q.getSingleResult();

                    q = em.createNamedQuery("Participe.findByEquipoIdTemporadaId");
                    q.setParameter("idEquipo", equipoExpulsado.getId());
                    q.setParameter("idTemporada", getTemporadaId());
                    Participe participeExpulsado = (Participe)q.getSingleResult();

                    participeExpulsado.setEstado((short)11);
                    participeExpulsado.setPuntos(0);

                    em.persist(participeExpulsado);

                    em.getTransaction().commit();
                }

                boolean hayExpulsion = false; // Para mostrar el mensaje de alerta

                if (getUsuarioLogado()!=null) {
                    // Hay usuario logado
                    //log.debug("usaurio logado: " + getUsuarioLogado().getId());
                    //log.debug("administarador: " + torneo.getUsuario().getId());
                    if (getTorneo().getUsuario().getId().equals(getUsuarioLogado().getId())) {
                        // El usuario es el administrador del torneo
                        // Recorrer todo el calendario, y los partidos pendientes del usuario, dárselos por perdidos
                        if (getPartidosCalendario()!=null) {
                            for(DatosCalendarioTorneo listaCalendario : getPartidosCalendario()) {
                                for(Calendario partido : listaCalendario.getPartidos()) {
                                    // Ver si el equipoUrl coincide con algunos de los expulsados
                                    boolean expulsadoCasa = false;
                                    boolean expulsadoFuera = false;

                                    for (String url_equipo: getElegir_equipo()) {
                                        if (partido.getEquipo1().getNombreUrl().equals(url_equipo)) {
                                            expulsadoCasa = true;
                                        } else if (partido.getEquipo2().getNombreUrl().equals(url_equipo)) {
                                            expulsadoFuera = true;
                                        }
                                    }

                                    if ( expulsadoCasa || expulsadoFuera ) {

                                        hayExpulsion = true;

                                        // El partido es para expulsar a alguno
                                        if ( (partido.getEstado() == Calendario.ESTADO_NO_JUGADO) || (partido.getEstado() == Calendario.ESTADO_APLAZADO)) {
                                            //log.debug("El partido hay que darlo por perdido");

                                            int tanteo1 = 0;
                                            int tanteo2 = 0;

                                            if (expulsadoCasa && expulsadoFuera) {
                                                // Lo pierden los dos (estado = 2)
                                                actualizarTorneoUsuario(partido.getId(), 0, 2, new Date(), tanteo1, tanteo2);
                                            } else if (expulsadoCasa) {
                                                // Lo pierde el de casa (estado = 3)
                                                tanteo2 = 10;
                                                actualizarTorneoUsuario(partido.getId(), 0, 3, new Date(), tanteo1, tanteo2);
                                            } else {
                                                // Lo pierde el de fuera (estado = 3)
                                                tanteo1 = 10;
                                                actualizarTorneoUsuario(partido.getId(), 0, 3, new Date(), tanteo1, tanteo2);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (hayExpulsion) {
                    obtenerParticipes();
                }
            } catch (NoResultException e) {
                log.debug("[expulsar][temporada no encontrada]");
            } catch (Exception e) {
                log.error("Error:",e);
            } finally {
                try { em.close(); } catch (Exception e) { }
            }
        }//fin si se han seleccionado equipos a expulsar
        else{
            log.debug("[expulsar] No seleccionados");
            retorno = "no_selected";
        }
        
        return retorno;
    }

    private void actualizarTorneoUsuario( int idCalendario, int idPartido,
            int estado, Date fecha, int tanteo1, int tanteo2 ) {

        // Actualiza el resultado de un partido de un torneo de usuario
        // Si el estado pasado como parÃ¡metro es:
        //       1 actualiza el enfrentamiento como un partido jugado con normalidad
        //       2 perdido por ambos
        //       3 ganador decidido por el promotor

        EntityManager em = null;
        
        try {
            em = bsaadmin.getEmfAdmin().createEntityManager();

            // buscamos el calendario
            Query q = em.createNamedQuery("Calendario.findById");
            q.setParameter("id", idCalendario );
            Calendario cal = (Calendario)q.getSingleResult();

            if ( cal != null) {
                // actualizamos f_partido, tanteos y estado
                cal.setFPartido(fecha);
                cal.setTanteo1((short)tanteo1);
                cal.setTanteo2((short)tanteo2);
                cal.setEstado((short)12); // partido decido por el promotor
                //cal.setPartido(null);
                short ganados1=0,ganados2=0,perdidos1=0,perdidos2=0,puntos1=1,puntos2=1;

                em.getTransaction().begin();
                em.persist(cal);
                em.getTransaction().commit();

                switch ( estado) {
                    case 1:
                        if (tanteo1>tanteo2) {
                            puntos1 = 2;
                            puntos2 = 1;
                            ganados1 = 1;
                            perdidos2 = 1;
                        } else {
                            puntos2 = 2;
                            puntos1 = 1;
                            ganados2 = 1;
                            perdidos1 = 1;
                        }
                        break;
                    case 3:
                        if (tanteo1>tanteo2) {
                            puntos1 = 2;
                            puntos2 = 0;
                            ganados1 = 1;
                            perdidos2 = 1;
                        } else {
                            puntos2 = 2;
                            puntos1 = 0;
                            ganados2 = 1;
                            perdidos1 = 1;
                        }
                        break;
                    case 2:
                        perdidos1 = 1;
                        perdidos2 = 1;
                        puntos1 = 0;
                        puntos2 = 0;
                        break;
                    }

                // buscamos a los dos participles y
                // Actualizamos ganados, perdidos, puntos, y favor/contra
                actualizarParticipe( cal.getEquipo1().getId(), cal.getTemporada().getId(),
                        puntos1, ganados1, perdidos1, tanteo1, tanteo2 );
                actualizarParticipe( cal.getEquipo2().getId(), cal.getTemporada().getId(),
                      puntos2, ganados2, perdidos2, tanteo2, tanteo1 );
            }
        } catch (Exception e) {
            log.error("Error:",e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }
    }

    private void actualizarParticipe(int idEquipo, int idTemporada, int puntos,
            short ganados, short perdidos,  int favor, int contra ) {

        EntityManager em = null;

        try {
            em = bsaadmin.getEmfAdmin().createEntityManager();
            //log.debug("Buscando Participe "+ idEquipo + " "+ idTemporada+ " PUNTOS"+puntos);
            Query qp = em.createNamedQuery("Participe.findByEquipoIdTemporadaId");
            qp.setParameter("idEquipo", idEquipo);
            qp.setParameter("idTemporada", idTemporada  );
            Participe participe = (Participe)qp.getSingleResult();

            //log.debug("participe encontrado: " + participe);
            //log.debug("equipo: " + participe.getEquipo());
            //log.debug("idEquipo: " + participe.getEquipo().getId());

            if ( participe != null ) {
                participe.setFavor  (participe.getFavor ()+favor);
                participe.setContra (participe.getContra()+contra);

                participe.setGanados((short)(participe.getGanados()+ganados));
                participe.setPerdidos((short)(participe.getPerdidos()+perdidos));
                participe.setPuntos(participe.getPuntos()+puntos);

                //log.debug("persistiendo ...");

                em.getTransaction().begin();
                em.persist(participe);
                em.getTransaction().commit();
            } else {
                log.info("Partícipe no encontrado");
            }
        } catch (Exception e) {
            log.error("Error:",e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }
    }

    @Override
    public String crear(){
        String retorno = SUCCESS;

        log.debug("[crear] Datos: " + administrador + "-" + getNombre_torneo() + "-" +
        getTipo_torneo() + "-" + getContrasenya_torneo() +  "-" + getNumero_participantes() + "-" +
        getNumero_entre() + "-" + getNumero_y() + "-" +  getFrecuencia() +  "-" +
        getEquipo_inscrito() + "-" + getInvitaciones() + "-" + getDescripcion());

        EntityManager em = null;
        try {
            // Comprobaciones previas
            boolean cumpleComprobaciones = true;

            em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

            Pattern pt = Pattern.compile(patternNombreTorneoAdmin);
            if (getNombre_torneo()!=null) {
                if (!Pattern.matches(patternNombreTorneoAdmin,getNombre_torneo())) {
                    cumpleComprobaciones = false;
                    log.debug("[Crear] Torneo No cumple patron");
                } else {
                    if (getNombre_torneo().length()<=0 || getNombre_torneo().length()>34) {
                        cumpleComprobaciones=false;
                        log.debug("[Crear] Torneo No cumple nombre/longitud");
                    }
                }
            } else {
                cumpleComprobaciones = false; // nombre no puede ser null
                log.debug("[Crear] Torneo nombre vacio");
            }

            if (getNumero_entre() > getNumero_y()) {
                short aux = getNumero_y();
                setNumero_y(getNumero_entre());
                setNumero_entre(aux);
            }
            if (getNumero_participantes()<4 || getNumero_participantes()>8) {
                cumpleComprobaciones=false;
                log.debug("[Crear] Torneo numero participantes menor de 4 o mayor de 8");
            }

            Usuario usuario = null;
            //comprobamos que el usuario pasado como administrador existe en la BD
            if(administrador!=null && administrador.compareTo("")!=0){
                Query q = em.createNamedQuery("Usuario.findByNick");
                q.setParameter("nick", administrador.toLowerCase());
                usuario = (Usuario)q.getSingleResult();
            }

            if (cumpleComprobaciones && usuario!=null) {

                log.debug("[Crear] Cumple comprobaciones y existe el usuario " + usuario.getNickMostrar());

                if (getNombre_torneo() != null) {

                    //Vemos cuantos torneos va a crear,si el nombre_torneo
                    //contiene #N# donde N es el numero de torneos a crear
                    //creamos esos N torneos,sino 1
                    int num = 1;

                    //buscamos un patron #N#
                    String partes[] = null;
                    String numString="";
                    if(getNombre_torneo().indexOf("#")!=-1){
                        numString = getNombre_torneo().substring((getNombre_torneo().indexOf("#")+1),getNombre_torneo().lastIndexOf("#"));
                        partes = getNombre_torneo().split("#"+numString+"#");
                        log.debug("[crear] numString: " + numString + " partes: " + partes.length);
                        num = Integer.parseInt(numString.trim());
                        log.debug("[crear] num: " + num);
                    }

                    String nombre_torneo = "";
                    Torneo torneo = null;
                    Temporada temporada = null;
                    TemporadaTrofeo temporadaTrofeo1 = null;
                    TemporadaTrofeo temporadaTrofeo2 = null;

                    for(int i=0;i<num;++i)
                    {
                        torneo = new Torneo();
                        temporada = new Temporada();

                        //montamos el nombre del torneo
                        if(partes!=null && partes.length>0){
                            if(partes.length==1){
                                int indice_texto = getNombre_torneo().indexOf(partes[0]);
                                int patron = getNombre_torneo().indexOf("#"+num+"#");
                                if(indice_texto < patron){
                                    //caso: nombre____X
                                    nombre_torneo = partes[0] + (i+1);
                                }else{
                                    //caso: X____nombre
                                    nombre_torneo = (i+1) + partes[0];
                                }
                            }else{
                                //caso: nombre____X____nombre
                                nombre_torneo = partes[0] + (i+1) + partes[1];
                            }
                        }else{
                            nombre_torneo = getNombre_torneo();
                        }
                        log.debug("[crear] nombre: " + nombre_torneo);

                        torneo.setNombre(nombre_torneo);
                        //añadimos el usuario pasado por parametro
                        UsuarioParcial user = em.find(UsuarioParcial.class, usuario.getId());
                        torneo.setUsuario(user);
                        torneo.setNombreUrl(getNombreUrl(nombre_torneo));
                        torneo.setDescripcion(getDescripcion());
                        temporada.setEdicion((short)1); // Primera temporada
                        temporada.setMaxEquipos(getNumero_participantes());
                        temporada.setNivelIni(getNumero_entre());
                        temporada.setNivelFin(getNumero_entre());
                        temporada.setFrecuencia((short)getFrecuencia());
                        temporada.setTiempoCuarto((short)2);
                        temporada.setCartas((short)1);
                        temporada.setTalentos((short)1);
                        temporada.setJornadas((short)(getNumero_participantes()*2-2));

                        // Poner la fecha de inicio como actual para borrar las temporadas que lleven mucho tiempo sin inicarse
                        temporada.setFInicio(new Date());

                        mandarInvitaciones(false);

                        em.getTransaction().begin();
                        em.persist(torneo);

                        temporada.setTorneo(torneo);
                        temporada.setEstado((short)1); // Período inscripción
                        temporada.setTipo((short)1); // Tipo 1 = liga

                        //log.debug("Tipo torneo en creacion: " + tipo_torneo);
                        if (getTipo_torneo().equals("privado")) {
                            temporada.setPrivada((short)1);
                            temporada.setPassword(getContrasenya_torneo());
                        } else {
                            temporada.setPrivada((short)0);
                        }

                        //temporada.setTorneoId(torneo.getId());
                        em.persist(temporada);

                        // Asignar temporada_trofeo
                        temporadaTrofeo1 = new TemporadaTrofeo(temporada.getId(),ID_TROFEO_POSICION_1,(short)1);
                        temporadaTrofeo2 = new TemporadaTrofeo(temporada.getId(),ID_TROFEO_POSICION_2,(short)2);
                        em.persist(temporadaTrofeo1);
                        em.persist(temporadaTrofeo2);

                        em.getTransaction().commit();
                    }
                    //redirigimos al torneo en cuestion
                    setUrl(torneo.getNombreUrl());
                    retorno = REDIRECT;
                }
            }
        } catch (Exception e) {
            log.error("[torneos crear]: ", e);
            retorno = ERROR;
        } finally {
            try { if (em.getTransaction().isActive()){ em.getTransaction().rollback();} } catch (Exception e) { }
            try { em.close(); } catch (Exception e) { }
        }

        return retorno;
    }

    @Override
    public String equipos() {
        String retorno ="";

        retorno = super.equipos();
        
        dameListaEquipos();
        
        return retorno;
    }

    public String dameListaEquipos(){
        ListaEquipos lequi = new ListaEquipos();

        log.debug("[dameListaEquipos] entro");

        if(getCuantos()>0){
            lequi.setCuantos(getCuantos());
        }else{
            lequi.setCuantos(LISTADO_RESULTADOS_ELEMENTOS_POR_PAGINA);
        }

        lequi.setLetras("todos");

        if(getPagina()>1){
            lequi.setPagina(getPagina());
        }else{
            lequi.setPagina(1);
        }

        lequi.execute();

        log.debug("[dameListaEquipos] equipos: " +lequi.getDatos());

        setListaEquipos(lequi.getDatos());
        setCabecera(lequi.getCabecera());

        return SUCCESS;
    }

    public String apuntarEquipo(){

        EntityManager em = null;
        try {
            // Comprobaciones previas
            em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

            //busco la temporada
            log.debug("[apuntarEquipo] Temporada: " + getTemporadaId());
            
            Temporada temporada = null;

            Query q = em.createNamedQuery("Temporada.findById");
            q.setParameter("id", getTemporadaId());

            temporada = (Temporada)q.getSingleResult();

            //busco el equipo
            log.debug("[apuntarEquipo] Equipo: " + getIdEquipo());

            Equipo e = null;

            //q = em.createNamedQuery("Equipo.findByNombreUrl");
            //q.setParameter("nombre", getUrlEquipo());

            q = em.createNamedQuery("Equipo.findById");
            q.setParameter("idEquipo", getIdEquipo());

            e = (Equipo)q.getSingleResult();

            //si todo bien, apuntamos el equipo en el torneo
            if(temporada!=null && e!=null){
                int ret = ListaTorneosUsuario.apuntarse(temporada,e,temporada.getPassword(), log, em);
                
                //ahora le cambio su estado de 0=Peticion a 1=Inscrito si puede participar
                if(ret>0){
                    q = em.createNamedQuery("Participe.findByEquipoIdTemporadaId");
                    q.setParameter("idEquipo", e.getId());
                    q.setParameter("idTemporada", temporada.getId());

                    Participe p = (Participe)q.getSingleResult();

                    p.setEstado((short)1);

                    em.getTransaction().begin();
                    em.persist(p);
                    em.getTransaction().commit();
                }else{
                    log.debug("[apuntarEquipo] No puede inscribirse a este equipo en el torneo.");
                    return "error_nivel";
                }
            }else{
                return ERROR;
            }
        } catch (Exception e) {
            log.error("[apuntarEquipo]: ", e);
        } finally {
            try { if (em.getTransaction().isActive()){ em.getTransaction().rollback();} } catch (Exception e) { }
            try { em.close(); } catch (Exception e) { }
        }

       return SUCCESS;
    }

    public boolean getNotSelected() {
        return notSelected;
    }

    public void setNotSelected(boolean notSelected) {
        this.notSelected = notSelected;
    }

    public int getTemporadaId() {
        return temporadaId;
    }

    public void setTemporadaId(int temporadaId) {
        this.temporadaId = temporadaId;
    }

    public String getAdministrador() {
        return administrador;
    }

    public void setAdministrador(String administrador) {
        this.administrador = administrador;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List<Equipo> getListaEquipos() {
        return listaEquipos;
    }

    public void setListaEquipos(List<Equipo> listaEquipos) {
        this.listaEquipos = listaEquipos;
    }

    public String getUrlEquipo() {
        return urlEquipo;
    }

    public void setUrlEquipo(String urlEquipo) {
        this.urlEquipo = urlEquipo;
    }

    public boolean isError() {
        return error;
    }

    public void setError(boolean error) {
        this.error = error;
    }

    public String getPatternCrear() {
        return patternCrear;
    }

    public void setPatternCrear(String patternCrear) {
        this.patternCrear = patternCrear;
    }

    public String getPatternNombreTorneoAdmin() {
        return patternNombreTorneoAdmin;
    }

    public void setPatternNombreTorneoAdmin(String patternNombreTorneoAdmin) {
        this.patternNombreTorneoAdmin = patternNombreTorneoAdmin;
    }

    public int getIdEquipo() {
        return idEquipo;
    }

    public void setIdEquipo(int idEquipo) {
        this.idEquipo = idEquipo;
    }

    public String getError_nivel() {
        return error_nivel;
    }

    public void setError_nivel(String error_nivel) {
        this.error_nivel = error_nivel;
    }

    public BaseActionAdmin getBsaadmin() {
        return bsaadmin;
    }

    public void setBsaadmin(BaseActionAdmin bsaadmin) {
        this.bsaadmin = bsaadmin;
    }
}


